// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System;
using System.Collections.Generic;
using Antlr4.Runtime.Tree;
using Microsoft.Extensions.DependencyInjection;

namespace SnapObjects.Expressions
{
    internal class ExpressionVisitor<T> : AbstractParseTreeVisitor<T>, IExpressionVisitor<T>
    {
        private readonly Type _terminal = typeof(ITerminalNode);
        private readonly IDictionary<Type, INodeExpressionVisitor<T>> _visitors;

        public ExpressionVisitor(IServiceProvider provider)
        {
            _visitors = new Dictionary<Type, INodeExpressionVisitor<T>>();

            var visitors = provider.GetServices<INodeExpressionVisitor<T>>();

            foreach (var visitor in visitors)
            {
                _visitors[visitor.NodeType] = visitor;
            }
        }

        public T Visit(IParseTree tree, ParserOptions<T> options)
        {
            var type = tree is ITerminalNode ? _terminal : tree.GetType();

            if (_visitors.TryGetValue(type, out var visitor))
            {
                return visitor.Visit(this, tree, options);
            }

            if (tree is IRuleNode node)
            {
                return this.VisitChildren(node, options);
            }

            return default;
        }

        private T VisitChildren(IRuleNode node, ParserOptions<T> options)
        {
            var result = default(T);

            for (var i = 0; i < node.ChildCount; i++)
            {
                if (!this.ShouldVisitNextChild(node, result))
                {
                    break;
                }

                var child = node.GetChild(i);

                var childResult = this.Visit(child, options);

                result = this.AggregateResult(result, childResult);
            }

            return result;
        }
    }
}
